home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 23
/
Aminet 23 (1998)(GTI - Schatztruhe)[!][Feb 1998].iso
/
Aminet
/
text
/
edit
/
Smartindent.lha
/
Smartindent
/
Source
/
util.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-12-14
|
13KB
|
523 lines
/*(( "Kopf" */
/* -----------------------------------------------------------------------------
$Id: util.c,v 1.4 1997/06/29 19:24:13 mshopf Exp mshopf $
GoldED API client, ©1997 Matthias Hopf.
Compiled with SasC.
Utility functions.
------------------------------------------------------------------------------
*/
/*)) */
/*(( "Includes" */
#include "smartindent.h"
#include "util.h"
#include "semantics.h"
#include <proto/exec.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <string.h>
#include <ctype.h>
/*)) */
/*(( "Daten" */
struct Semantic *Semantics[] = SEMANTICS;
int ExecVersion;
int MemAllocSmallFlags;
#ifdef DEBUG
int Dbug_Counter;
int Dbug = 0;
#endif
/* Common parser errors */
const char *SYNTAX_ERROR = "Syntax error in line %ld";
const char *UNMATCHED_BRACE_ERROR = "Unmached brace in line %ld";
const char *PRAEPROCESSOR_ERROR = "Praeprocessor error in line %ld";
const char *SUSPICIOUS_ERROR = "Suspicious statement in line %ld";
const char *STRING_TERMINATION_ERROR = "Non-terminated string above line %ld";
const char *INTERNAL_ERROR = "!!! Internal parse error in line %ld !!!";
const char *UNKNOWN_MODE_ERROR = "Unknown MODE. Known modes are:\n" SEMANTICS_NAMES;
const char *UNSPECIFIED_MODE_ERROR = "No MODE specified (mandatory). Known modes are:\n" SEMANTICS_NAMES;
/*)) */
/********** Private **********/
/*(( "NewRequest ()" */
/* Create and initialize new APIOrder and APIModifyRequest.
* Create a (maximum sized) string, too. */
static struct SmartOrder *NewRequest (sc_t *c, int Line, int Size)
{
struct SmartOrder *o;
if (! (o = AllocMem (sizeof (struct SmartOrder) + Size, MemAllocSmallFlags)) )
{
Error (c, "Out of memory in line %d");
return NULL;
}
o->Order.api_Data = &o->Modify;
o->Modify.mr_Line = Line;
o->Modify.mr_Data = OrderString (o);
o->StringSize = Size;
return (o);
}
/*)) */
/*(( "LinkRequest ()" */
/* Link outstanding Order to message. */
static void LinkRequest (sc_t *c, struct SmartOrder *o)
{
if (o)
{
o->Order.api_Next = c->Msg->api_Order;
c->Msg->api_Order = &o->Order;
}
}
/*)) */
/*(( "DoRequest ()" */
/* Create/modify Order for the current line, but the given position.
* Old Orders are linked or expanded when necessary.
* No indentation correctness is checked, no Client values are addapted! */
static void DoRequest (sc_t *c, int Pos, int Indent)
{
struct SmartOrder *o = c->Req;
char *Text;
int Len, Needed;
/* Link old Request, when it is not one for the current line */
if (o && c->CurrentLine != o->Modify.mr_Line)
{
debug (D_REQUESTS, ("Linking for line %ld\t", o->Modify.mr_Line));
LinkRequest (c, o);
c->Req = o = NULL;
}
GetText (c, &Text, &Len);
Needed = Indent > 0 ? Len + Indent : Len;
/* Create new Request when necessary */
if (! o)
{
debug (D_REQUESTS, ("New Req for line %ld\t", c->CurrentLine));
if (! (c->Req = o = NewRequest (c, c->CurrentLine, Needed + ADD_SPARSE_INDENTATION)) )
return;
memcpy (OrderString (o), Text, Len);
o->Modify.mr_Size = Len;
}
/* else check size of current Request and copy it to a new one when necessary */
else if (o->StringSize < Needed)
{
debug (D_REQUESTS, ("Renew Req for line %ld old size %ld needed %ld\t", c->CurrentLine, o->StringSize, Needed));
if (! (o = NewRequest (c, c->CurrentLine, Needed + ADD_SPARSE_INDENTATION)) )
return;
memcpy (OrderString (o), Text, Len);
o->Modify.mr_Size = Len;
FreeRequest (c, c->Req);
c->Req = o;
}
/* Now shift characters */
memmove (OrderString (o) + Pos + Indent, OrderString (o) + Pos, o->Modify.mr_Size - Pos);
if (Indent > 0)
memset (OrderString (o) + Pos, ' ', Indent);
o->Modify.mr_Size += Indent;
}
/*)) */
/*(( "DoneCursorLine ()" */
/* We have indented the current cursor line.
* Now set Cursor pos to something reasonable (when necessary). */
static void DoneCursorLine (sc_t *c)
{
char *Text;
int Len, i;
if (! (c->Mode & MODE_CURSOR))
return;
GetText (c, &Text, &Len);
debug (D_CURSOR, ("\nchecking line %ld, len %ld, indent %ld, cursorpos %ld\n", c->CurrentLine, Len, c->Indent, c->CursorX));
for (i = 0; i < Len; i++)
if (! isspace (Text [i]))
break;
debug (D_CURSOR, ("first non-space pos %ld\n", i));
if (i < Len)
{
if (c->CursorX < i) /* current cursorpos less than first char pos */
c->CursorX = i;
for (i = Len-1; i >= 0; i--)
if (! isspace (Text [i]))
break;
i++;
debug (D_CURSOR, ("last non-space pos %ld, last non-space char 0x%lx\n", i-1, i> 0 ? (long) Text[i-1] : (long) '/'));
if (c->CursorX > i) /* current cursorpos greater than last char pos */
c->CursorX = i;
}
else /* empty line */
c->CursorX = c->Indent;
}
/*)) */
/********** Public **********/
/*(( "InitIndent ()" */
void InitIndent (sc_t *c, int BeginLine, int EndLine, int Mode)
{
struct EditConfig *Edit = c->Edit;
debug (Dbug, ("Startline %ld, EndLine %ld, Mode 0x%lx\n", BeginLine, EndLine, Mode));
memset (& (c->FirstLine), 0, sizeof (sc_t) - offsetof (sc_t, FirstLine));
c->BeginIndent = BeginLine;
c->EndIndent = EndLine;
c->Mode = Mode;
c->LastPos = -1;
c->FirstLine = c->CurrentLine = 0; /* scan for first column "{" later */
c->Node = Edit->TextNodes;
c->BlockStartX = Edit->BlockStartX;
c->BlockEndX = Edit->BlockEndX;
c->CursorX = Edit->Column;
}
/*)) */
/*(( "CleanupIndent ()" */
void CleanupIndent (sc_t *c)
{
struct SmartOrder *o, **next, **last;
struct EditConfig *Edit = c->Edit;
struct LineNode *Nodes = Edit->TextNodes;
/* Link last request */
LinkRequest (c, c->Req);
c->Req = NULL;
/* Check requests, whether they are really necessary */
last = (struct SmartOrder **) & (c->Msg->api_Order);
o = *last;
while (o)
{
next = (struct SmartOrder **) & (o->Order.api_Next);
debug (D_REQUESTS, ("checking request %lx for line %ld, next: %lx, last pointer: %lx\n", o, o->Modify.mr_Line, *next, last));
if (o->Modify.mr_Size == Nodes [o->Modify.mr_Line] .Len)
{
if (strncmp ((UBYTE *) (o+1), Nodes [o->Modify.mr_Line] .Text, o->Modify.mr_Size) == 0)
{
debug (D_REQUESTS, ("Freeing unnecessary request %lx for line %ld.\n", o, o->Modify.mr_Line));
*last = *next;
FreeRequest (c, o);
next = last;
}
}
last = next;
o = *last;
}
/* Update display if necessary */
#if 0
if (c->Msg->api_Order)
c->Msg->api_Refresh |= 0;
#endif /* Not necessary in current GoldEd version. */
/* Create cursor move requests when necessary */
if (c->CursorX != Edit->Column)
if ( (o = NewRequest (c, Edit->Line, 0)) )
{
o->Modify.mr_Data = NULL;
o->Modify.mr_Column = c->CursorX;
LinkRequest (c, o);
c->Msg->api_Refresh |= API_REFRESH_SYNC;
}
/* Update block markers if necessary */
if (c->BlockStartX != Edit->BlockStartX || c->BlockEndX != Edit->BlockEndX)
{
Edit->BlockStartX = c->BlockStartX;
Edit->BlockEndX = c->BlockEndX;
c->Msg->api_Refresh |= API_REFRESH_MARKER;
}
#ifdef DEBUG
if (Dbug & D_REQUESTS)
{
Printf ("Orders for lines ");
o = (struct SmartOrder *) c->Msg->api_Order;
while (o)
{
Printf ("%ld ", o->Modify.mr_Line);
o = (struct SmartOrder *) o->Order.api_Next;
}
Printf ("%%\n");
}
#endif
}
/*)) */
/*(( "FreeRequest ()" */
/* Free the APIOrder, APIModifyRequest and the string space. */
void FreeRequest (sc_t *c, struct SmartOrder *Req)
{
debug (D_REQUESTS, ("Freeing request for line %ld\t", Req->Modify.mr_Line));
FreeMem (Req, sizeof (struct SmartOrder) + Req->StringSize);
}
/*)) */
/*(( "GetText ()" */
/* Get *real* current text and length */
void GetText (sc_t *c, char **Text, int *Len)
{
if (c->Req && c->Req->Modify.mr_Line == c->CurrentLine)
{
*Text = OrderString (c->Req);
*Len = c->Req->Modify.mr_Size;
}
else if (c->Edit->Line == c->CurrentLine && c->Edit->CurrentBuffer)
{
*Text = c->Edit->CurrentBuffer;
*Len = c->Edit->CurrentLen;
}
else
{
*Text = c->Node->Text;
*Len = c->Node->Len;
}
}
/*)) */
/*(( "Move ()" */
/* Move current line contents at position Pos when indentation is enabled
* for the current line.
* Perform indentation correctness checks. */
void Move (sc_t *c, int Pos, int NewPos)
{
char *text;
int len, i, line;
if (Pos == NewPos)
return;
debug (D_MOVE, ("Move(%ld->%ld)[Cur %ld]\t", Pos, NewPos, c->CurrentPos));
line = c->CurrentLine;
/* don't do anything when we are out of limits */
if (line < c->BeginIndent || line > c->EndIndent)
return;
if (NewPos < 0)
NewPos = 0;
GetText (c, &text, &len);
if (len < 1)
{
Error (c, "Move () on empty line %d!");
return;
}
/* When there's nothing to shift, exit */
if (Pos >= len)
return;
/* Backindent only as far as we are only killing spaces */
if (NewPos < Pos)
{
/* We want at least one space before the new position */
for (i = Pos+1; i > NewPos; i--)
if (i >= 2 && text [i-2] != ' ')
break;
/* We cannot shift without breaking the rules */
if (i >= Pos)
return;
NewPos = i;
}
i = NewPos - Pos;
DoRequest (c, Pos, i);
if (c->CurrentPos >= Pos)
c->CurrentPos += i;
if (c->NextPos >= Pos)
c->NextPos += i;
if (c->NextPosEOL >= Pos)
c->NextPosEOL += i;
if (line == c->Edit->Line && c->CursorX >= Pos)
c->CursorX += i;
if (line == c->Edit->BlockStartY && c->BlockStartX >= Pos)
c->BlockStartX += i;
if (line == c->Edit->BlockEndY && c->BlockEndX >= Pos)
c->BlockEndX += i;
debug (D_MOVE, ("Res(%ld)[Cur %ld]\t", i, c->CurrentPos));
}
/*)) */
/*(( "NextWord ()" */
/* Get the next word (maximum length MAX_WORD_LEN-1).
* Returns an empty word after EOF.
* Sets Current* when Flag is set. */
void NextWord (sc_t *c, char *buf, int Flag)
{
char *text;
int len, i, res;
int line = c->CurrentLine;
int pos = c->NextPos;
int last = c->CurrentPos;
struct LineNode *n = c->Node;
char *copy = buf;
int (*IsWord) (struct SmartClient *c, char *buf, int len, int maxlen) = c->Sem->IsWord;
*buf = '\0';
/* We may continue to scan the current line */
GetText (c, &text, &len);
/* Has an unget happened? */
if (last == pos)
last = -1;
for (;;)
{
/* First make sure we have something to scan. */
if (pos < 0 || pos >= len || IS_FOLD (n))
{
if (line == c->Edit->Line && Flag)
{
c->CurrentLine = line;
c->Node = n;
DoneCursorLine (c);
}
if (++line >= c->Edit->Lines)
{
c->CurrentLine = c->EndIndent +1; /* we are finished */
return;
}
n++;
/* not nice - this should be able to use GetText()... */
if (c->Edit->Line == line && c->Edit->CurrentBuffer)
{
text = c->Edit->CurrentBuffer;
len = c->Edit->CurrentLen;
}
else
{
text = n->Text;
len = n->Len;
}
pos = 0;
last = -1;
continue;
}
/* Then skip whitespace */
if (! isspace (text[pos]))
break;
pos++;
}
/* Now copy chars as long as they belong to the word and they fit into the buffer */
res = MATCH_FALSE;
for (i = pos; i < len && copy < buf + MAX_WORD_LEN-1; )
{
if ( (res = (*IsWord) (c, &text [pos], i-pos+1, len-pos)) == MATCH_FALSE )
break;
*copy++ = text [i++];
*copy = '\0';
if (res == MATCH_EXACT)
break;
}
/* Adapt Environment when Flag is set */
if (! Flag)
{
debug (D_WORD, ("%ld<%s>\t", pos, buf));
return;
}
/* Now skip remaining chars as long as they belong to the word */
if (res == MATCH_TRUE)
while (i < len && (res = (*IsWord) (c, &text [pos], i-pos+1, len-pos)) != MATCH_FALSE)
{
i++;
if (res == MATCH_EXACT)
break;
}
/* Now skip whitespace */
while (i < len && isspace (text [i]))
i++;
if (i >= len)
i = -1;
debug (D_WORD, ("%ld%s%s[%s]\t", pos, last < 0 ? "b" : "", i < 0 ? "e" : "", buf));
c->CurrentLine = line;
c->CurrentPos = pos;
c->Node = n;
c->NextPos = c->NextPosEOL = i;
c->LastPos = last;
}
/*)) */
/*(( "LastWord ()" */
void LastWord (sc_t *c)
{
int i;
c->NextPos = c->NextPosEOL = c->CurrentPos;
c->LastPos = -1;
for (i = c->CurrentPos-1; i >= 0; i--)
if (! isspace (c->WordBuffer [i]))
{
c->CurrentPos = i;
return;
}
c->CurrentPos = -1;
}
/*)) */